package jpf.nextsearch.front.controller;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jpf.nextsearch.base.GenericFormController;
import jpf.nextsearch.ds.model.types.ResourceServiceType;
import jpf.nextsearch.ds.model.types.ResourceType;
import jpf.nextsearch.front.command.SearchFormCommand;
import jpf.nextsearch.front.model.SearchFormModel;
import jpf.nextsearch.search.ResourceSearcher;
import jpf.nextsearch.search.model.SearchRequest;
import jpf.nextsearch.search.model.SearchResponse;
import jpf.nextsearch.util.Toolkit;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.web.servlet.ModelAndView;

/**
 * @author <a href="mailto:jacek.pruszkowski@gmail.com">Jacek Pruszkowski</a>
 */
@SuppressWarnings("deprecation")
public class SearchFormController extends GenericFormController {

	public static final String PARAM_QUERY = "query";
	
	private ResourceSearcher resourceSearcher;
	
	private int maxResultsPerPage;
	
	static int c = 0;

	public SearchFormController() {
		if (isLoggingDebug()) {
			getLogger().debug("SearchFormController -> contructor ...");
		}
		setLogger(Logger.getLogger(this.getClass()));
	}

	@Override
	protected Object formBackingObject(HttpServletRequest request) {
		SearchFormCommand command = new SearchFormCommand();
		command.setResourceType(-1);
		command.setSearchType(SearchRequest.SEARCH_TYPE_NAME_ONLY);
		return command;
	}

	protected Map<String, Object> referenceData(HttpServletRequest request,
			Object command, Errors errors) {
		SearchFormModel searchFormModel = new SearchFormModel();
		prepareModel(searchFormModel);
		Map<String, Object> model = new HashMap<String, Object>();
		model.put("model", searchFormModel);
		return model;
	}

	@Override
	protected ModelAndView onSubmit(HttpServletRequest request,
		HttpServletResponse response, Object command, BindException errors) 
		throws Exception {
		try {
			c++;//XXXX
			System.out.println(c);
	
			if (isLoggingDebug()) {
				getLogger().debug("SearchFormController -> onSubmit ...");
			}
			SearchFormCommand searchFormCommand = (SearchFormCommand) command;
			if (isLoggingDebug()) {
				getLogger().debug("SearchFormCommand:\n"+Toolkit.objectToString(searchFormCommand));
			}		
			SearchFormModel searchFormModel = new SearchFormModel();
			prepareModel(searchFormModel);
			Map<String, Object> model = new HashMap<String, Object>();
			model.put("model", searchFormModel);
			SearchRequest searchRequest = prepareSearchRequest(searchFormCommand, searchFormModel);
			if (searchRequest != null) {
				SearchResponse searchResponse = getResourceSearcher().searchResources(searchRequest);
				searchFormModel.setSearchResponse(searchResponse);
			} else {
				if (isLoggingDebug()) {
					getLogger().debug("skipping search, searchRequest is invalid");
				}		
			}
			return this.mergeModels(super.onSubmit(request, response,
					searchFormCommand, errors), model);
			
		} catch (Exception e) {
			return handleGeneralError(request, response, e);
		}
	}
	
	private SearchRequest prepareSearchRequest(SearchFormCommand command, SearchFormModel model) {
		SearchRequest searchRequest = new SearchRequest();
		
		if (StringUtils.isBlank(command.getQuery())) {
			return null;
		}
		searchRequest.setQuery(command.getQuery().trim());
		
		Integer searchType = command.getSearchType();
		if (searchType == null || 
			(!searchType.equals(SearchRequest.SEARCH_TYPE_NAME_AND_PATH) &&
			 !searchType.equals(SearchRequest.SEARCH_TYPE_NAME_ONLY) &&
			 !searchType.equals(SearchRequest.SEARCH_TYPE_PATH_ONLY))) {
			return null;
		}
		searchRequest.setSearchType(searchType);		
		
		if (command.getResourceType() != null && ResourceType.fromInt(command.getResourceType()) != null) {
			searchRequest.setResourceType(ResourceType.fromInt(command.getResourceType()));
		}
		
		if (command.getServiceType() != null && ResourceServiceType.fromInt(command.getServiceType()) != null) {
			searchRequest.setResourceServiceType(ResourceServiceType.fromInt(command.getServiceType()));
		}
		
		searchRequest.setSearchActiveHostsOnly(Boolean.TRUE.equals(command.getActiveOnly()));
		searchRequest.setMaxResults(getMaxResultsPerPage());
		return searchRequest;
	}

	private void prepareModel(SearchFormModel model) {
		List<Integer> resourceTypes = new ArrayList<Integer>();
		for (ResourceType rt : ResourceType.values()) {
			resourceTypes.add(rt.toInt());
		}
		resourceTypes.add(-1);
		model.setResourceTypes(resourceTypes);
		
		List<Integer> serviceTypes = new ArrayList<Integer>();
		for (ResourceServiceType rst : ResourceServiceType.values()) {
			serviceTypes.add(rst.toInt());
		}
		serviceTypes.add(-1);
		model.setServiceTypes(serviceTypes);
		
		Integer[] searchTypes = new Integer[] {SearchRequest.SEARCH_TYPE_NAME_ONLY,
			SearchRequest.SEARCH_TYPE_NAME_AND_PATH,
			SearchRequest.SEARCH_TYPE_PATH_ONLY};
		model.setSearchTypes(Arrays.asList(searchTypes));
	}
	
	/**
	 * wszystkie requesty traktujemy jako post formularza -> spojny flow i
	 * daje mozliwosc traktowania klikania w linki paginacji jako search 
	 */
	protected boolean isFormSubmission(HttpServletRequest request) {
		return true;
	}

	public void setResourceSearcher(ResourceSearcher resourceSearcher) {
		this.resourceSearcher = resourceSearcher;
	}

	public ResourceSearcher getResourceSearcher() {
		return resourceSearcher;
	}

	public void setMaxResultsPerPage(int maxResultsPerPage) {
		this.maxResultsPerPage = maxResultsPerPage;
	}

	public int getMaxResultsPerPage() {
		return maxResultsPerPage;
	}

}
